package com.shanzhu.volunteer.modules.ai.service;

import com.shanzhu.volunteer.modules.ai.dto.RecommendationDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

// 引入相关仓库接口和实体 (假设路径)
import com.shanzhu.volunteer.persistent.dataobject.CeCollege;
import com.shanzhu.volunteer.persistent.repository.ICeCollegeRepo;
import com.shanzhu.volunteer.persistent.dataobject.CeProfession;
import com.shanzhu.volunteer.persistent.repository.ICeProfessionRepo;
import com.shanzhu.volunteer.persistent.dataobject.CeScoreLine;
import com.shanzhu.volunteer.persistent.repository.ICeScoreLineRepo;

/**
 * 匹配算法
 */
@Component
public class MatchingAlgorithm {
    private static final Logger logger = LoggerFactory.getLogger(MatchingAlgorithm.class);

    @Autowired
    private XGBoostModelService xgBoostModelService;

    // 注入相关仓库
    @Autowired(required = false)
    private ICeCollegeRepo collegeRepo;

    @Autowired(required = false)
    private ICeProfessionRepo professionRepo;

    @Autowired(required = false)
    private ICeScoreLineRepo scoreLineRepo;

    /**
     * 计算学生与院校专业的匹配度
     * 
     * @param studentFeatures 学生特征
     * @param dimensions 分析维度
     * @param count 推荐数量
     * @return 推荐列表
     */
    public List<RecommendationDTO> calculateMatches(
            Map<String, Object> studentFeatures, 
            List<String> dimensions,
            int count) {
        
        if (collegeRepo == null || professionRepo == null || scoreLineRepo == null) {
             logger.warn("相关仓库未注入，无法进行匹配计算，返回备选推荐。");
             return generateFallbackRecommendations(count);
        }

        try {
            logger.info("开始计算匹配度，学生特征: {}, 维度: {}", studentFeatures, dimensions);
            
            // 获取学生分数
            float studentScore = getFloatValue(studentFeatures.get("score"));
            Integer studentRank = (Integer) studentFeatures.get("rank"); // 假设有排名
            
            // === 1. 从数据库获取候选院校和专业 ===
            // 实际应用中，应根据学生分数、位次、地区、选科等条件筛选候选池，而不是获取全部
            List<CeCollege> candidateColleges = collegeRepo.selectAllColleges(); // 假设获取所有院校
            if (candidateColleges == null || candidateColleges.isEmpty()) {
                logger.warn("未能从数据库获取到院校信息。");
                return generateFallbackRecommendations(count);
            }

            List<Map<String, Object>> optionsData = new ArrayList<>();
            List<float[]> featuresList = new ArrayList<>();

            // 获取最近一年的年份用于查询分数线 (模拟)
            Integer lastYear = scoreLineRepo.getLastYear(); // 假设此方法存在
            if (lastYear == null) lastYear = Calendar.getInstance().get(Calendar.YEAR) - 1; // 备选年份

            // === 2. 遍历候选院校和专业，构建特征 ===
            for (CeCollege college : candidateColleges) {
                // 获取该院校下的专业 (同样需要优化为按需获取)
                List<CeProfession> professions = professionRepo.selectProfessionByCollegeId(college.getId());
                 if (professions == null || professions.isEmpty()) {
                     continue; // 跳过没有专业的院校
                 }

                for (CeProfession profession : professions) {
                    Long collegeId = college.getId();
                    Long professionId = profession.getId(); // 假设有专业ID
                    String collegeName = college.getCollegeName();
                    String majorName = profession.getProfessionName();

                    // 模拟获取该专业的录取分数线/位次 (需要精确实现)
                    // CeScoreLine scoreLine = scoreLineRepo.selectScoreLineByYearAndProfession(lastYear, professionId);
                    // float admissionScore = scoreLine != null ? scoreLine.getScore() : generateMockAdmissionScore(collegeId, studentScore);
                    // Integer admissionRank = scoreLine != null ? scoreLine.getRank() : generateMockAdmissionRank(collegeId, studentRank);
                    // --- 占位符 ---
                    float admissionScore = generateMockAdmissionScore(collegeId, studentScore);
                    Integer admissionRank = generateMockAdmissionRank(collegeId, studentRank);


                    // --- 特征工程 (需要根据实际模型进行设计) ---
                    // 示例特征向量: [学生分数, 专业录取分, 学生位次, 专业录取位次, 院校层次得分, 专业热度得分]
                    float[] features = new float[6];
                    features[0] = studentScore;
                    features[1] = admissionScore;
                    features[2] = studentRank != null ? studentRank.floatValue() : 0f; // 处理 null
                    features[3] = admissionRank != null ? admissionRank.floatValue() : 0f; // 处理 null

                    // 模拟院校层次得分 (如 985=1.0, 211=0.8, 普通=0.5)
                    features[4] = generateMockCollegeTierScore(college);
                    // 模拟专业热度得分 (如 计算机=1.0, 电子=0.9, 机械=0.7)
                    features[5] = generateMockMajorHotnessScore(profession);

                    featuresList.add(features);

                    // 保存院校专业信息及用于后续处理的中间数据
                    Map<String, Object> option = new HashMap<>();
                    option.put("collegeId", collegeId);
                    option.put("collegeName", collegeName);
                    option.put("majorId", professionId); // 保存专业ID
                    option.put("majorName", majorName);
                    option.put("admissionScore", admissionScore); // 保存用于参考
                    option.put("admissionRank", admissionRank); // 保存用于参考
                    // 可以添加其他从数据库获取的属性，如院校特色、专业介绍等
                    // option.put("collegeFeature", college.getFeature());
                    // option.put("majorDescription", profession.getDescription());

                    optionsData.add(option);
                }
            }

            if (featuresList.isEmpty()) {
                 logger.warn("未能为任何院校专业构建特征向量。");
                 return generateFallbackRecommendations(count);
            }

            // === 3. 使用模型预测匹配度 ===
            float[][] featuresArray = featuresList.toArray(new float[0][]);
            // 调用 XGBoost 模型服务进行预测
            float[] matchingScores = xgBoostModelService.predictMatchingScores(featuresArray);

            // === 4. 构建推荐结果 ===
            List<RecommendationDTO> recommendations = new ArrayList<>();
            for (int i = 0; i < matchingScores.length; i++) {
                Map<String, Object> option = optionsData.get(i);

                RecommendationDTO rec = new RecommendationDTO();
                rec.setCollegeId((Long) option.get("collegeId"));
                rec.setCollegeName((String) option.get("collegeName"));
                 rec.setMajorId((Long) option.get("majorId")); // 添加专业ID
                rec.setMajorName((String) option.get("majorName"));
                rec.setMatchScore(matchingScores[i]); // 使用模型预测的分数

                // 生成推荐标签 (可以基于 option 中保存的特征或调用专门的标签服务)
                rec.setTags(generateRecommendationTags(studentFeatures, option, dimensions));

                recommendations.add(rec);
            }

            // === 5. 排序并返回前 N 个 ===
            return recommendations.stream()
                .sorted(Comparator.comparing(RecommendationDTO::getMatchScore).reversed())
                .limit(count)
                .collect(Collectors.toList());
                
        } catch (Exception e) {
            logger.error("匹配度计算错误", e);
            return generateFallbackRecommendations(count);
        }
    }
    
    /**
     * 生成推荐标签
     */
    private List<String> generateRecommendationTags(
            Map<String, Object> studentFeatures, 
            Map<String, Object> optionFeatures,
            List<String> dimensions) {
            
        List<String> tags = new ArrayList<>();
        
        // 根据不同维度生成标签
        if (dimensions.contains("interest")) {
            float interestMatch = generateInterestMatchScore(dimensions) / 100;
            if (interestMatch > 0.8) {
                tags.add("兴趣高度匹配");
            } else if (interestMatch > 0.6) {
                tags.add("兴趣较匹配");
            }
        }
        
        if (dimensions.contains("career")) {
            float careerProspect = (float) optionFeatures.get("careerProspect");
            if (careerProspect > 0.8) {
                tags.add("就业前景好");
            } else if (careerProspect > 0.6) {
                tags.add("就业前景较好");
            }
        }
        
        // 难度匹配
        float studentScore = getFloatValue(studentFeatures.get("score"));
        float admissionScore = (float) optionFeatures.get("admissionScore");
        if (studentScore > admissionScore + 30) {
            tags.add("录取概率高");
        } else if (studentScore > admissionScore) {
            tags.add("录取概率较高");
        } else {
            tags.add("录取有挑战");
        }
        
        // 添加专业特色标签
        tags.add((String) optionFeatures.get("majorFeature"));
        
        // 随机添加一些额外标签
        addRandomTags(tags, 1);
        
        return tags;
    }
    
    /**
     * 添加随机标签
     */
    private void addRandomTags(List<String> tags, int count) {
        Random random = new Random();
        for (int i = 0; i < count; i++) {
            String tag = TAG_POOL[random.nextInt(TAG_POOL.length)];
            if (!tags.contains(tag)) {
                tags.add(tag);
            }
        }
    }
    
    /**
     * 获取专业特色
     */
    private String getMajorFeature(String majorName) {
        Map<String, String> features = new HashMap<>();
        features.put("计算机科学与技术", "理论与实践并重");
        features.put("软件工程", "工程能力突出");
        features.put("人工智能", "前沿技术引领");
        features.put("数据科学与大数据技术", "大数据分析能力强");
        features.put("电子信息工程", "硬件软件结合");
        features.put("信息安全", "网络安全专业");
        features.put("物理学", "基础学科实力强");
        features.put("自动化", "控制理论扎实");
        features.put("通信工程", "5G技术领先");
        features.put("机械工程", "设计制造并重");
        
        return features.getOrDefault(majorName, "专业特色鲜明");
    }
    
    /**
     * 生成录取分数线
     */
    private float generateAdmissionScore(Long collegeId, float studentScore) {
        // 排名越靠前的院校，分数线越高
        int baseScore = 500;
        int maxIncrement = 150;
        float increment = (float) (maxIncrement * (1.0 - (collegeId - 1) / 10.0));
        
        // 添加一些随机波动
        Random random = new Random(collegeId);
        float noise = (random.nextFloat() - 0.5f) * 20;
        
        return baseScore + increment + noise;
    }
    
    /**
     * 生成兴趣匹配度分数
     */
    private float generateInterestMatchScore(List<String> dimensions) {
        // 基础匹配度
        float baseScore = 70.0f;
        
        // 如果包含兴趣维度，匹配度提升
        if (dimensions.contains("interest")) {
            baseScore += 10.0f;
        }
        
        // 添加随机波动
        Random random = new Random();
        float noise = (random.nextFloat() - 0.5f) * 15;
        
        return Math.min(100.0f, Math.max(50.0f, baseScore + noise));
    }
    
    /**
     * 生成就业前景分数
     */
    private float generateCareerProspectScore(Long collegeId) {
        // 基础就业前景
        float baseScore = 70.0f;
        
        // 排名靠前的院校就业前景更好
        baseScore += (10 - collegeId) * 2;
        
        // 添加随机波动
        Random random = new Random(collegeId);
        float noise = (random.nextFloat() - 0.5f) * 10;
        
        return Math.min(100.0f, Math.max(60.0f, baseScore + noise));
    }
    
    /**
     * 安全获取浮点值
     */
    private float getFloatValue(Object value) {
        if (value == null) {
            return 0.0f;
        }
        if (value instanceof Number) {
            return ((Number) value).floatValue();
        }
        try {
            return Float.parseFloat(value.toString());
        } catch (NumberFormatException e) {
            return 0.0f;
        }
    }
    
    /**
     * 生成备选推荐
     */
    private List<RecommendationDTO> generateFallbackRecommendations(int count) {
        logger.warn("生成备选推荐列表");
        List<RecommendationDTO> fallbackList = new ArrayList<>();
        Random random = new Random();

        // 模拟一些备选院校专业数据 (如果仓库查询失败)
        String[][] mockColleges = {
             {"9901", "模拟大学A", "模拟专业X"},
             {"9902", "模拟大学B", "模拟专业Y"},
             {"9903", "模拟大学C", "模拟专业Z"},
             {"9904", "模拟学院D", "模拟方向P"},
             {"9905", "模拟学院E", "模拟方向Q"}
        };

        int numToGenerate = Math.min(count, mockColleges.length);

        for (int i = 0; i < numToGenerate; i++) {
            RecommendationDTO rec = new RecommendationDTO();
             try {
                 rec.setCollegeId(Long.parseLong(mockColleges[i][0]));
             } catch (NumberFormatException e) {
                 rec.setCollegeId(9900L + i); // 备用ID
             }
            rec.setCollegeName(mockColleges[i][1]);
             // rec.setMajorId(...); // 模拟专业ID
            rec.setMajorName(mockColleges[i][2]);
            rec.setMatchScore(60 + random.nextDouble() * 15); // 60-75 的随机分数
            rec.setTags(Arrays.asList("备选推荐", random.nextBoolean() ? "综合考虑" : "潜力选项"));
            fallbackList.add(rec);
        }

        return fallbackList;
    }

    // --- 模拟方法 (需要替换为真实逻辑) ---

    /**
     * 模拟生成录取分数线
     */
    private float generateMockAdmissionScore(Long collegeId, float studentScore) {
         // 简单模拟：名次高的学校分数线相对高，并在学生分数附近波动
         Random random = new Random(collegeId);
         float baseScore = 650.0f - collegeId * 10; // 假设ID越小排名越高
         float fluctuation = (random.nextFloat() - 0.5f) * 50; // -25 到 +25 波动
         return Math.max(400f, Math.min(750f, baseScore + fluctuation));
    }

    /**
     * 模拟生成录取位次
     */
    private Integer generateMockAdmissionRank(Long collegeId, Integer studentRank) {
        if (studentRank == null) return null;
        Random random = new Random(collegeId + 1); // 使用不同种子
        int baseRank = 500 + collegeId.intValue() * 500; // 假设ID越小排名越靠前
        int fluctuation = (int)((random.nextDouble() - 0.5) * baseRank * 0.2); // ±10% 波动
        return Math.max(100, baseRank + fluctuation);
    }


    /**
     * 模拟生成院校层次得分
     */
     private float generateMockCollegeTierScore(CeCollege college) {
         // 需要根据 college 的属性 (如 is985, is211 字段) 来判断
         // 假设 CeCollege 有 is985(), is211() 方法
         // if (college.is985()) return 1.0f;
         // if (college.is211()) return 0.8f;
         // return 0.5f;
         // --- 占位符 ---
         if (college.getId() <= 5) return 1.0f; // 模拟前5个是顶尖
         if (college.getId() <= 10) return 0.8f; // 模拟前10个是重点
         return 0.5f;
     }

    /**
     * 模拟生成专业热度得分
     */
     private float generateMockMajorHotnessScore(CeProfession profession) {
         String name = profession.getProfessionName();
         if (name == null) return 0.5f;
         if (name.contains("计算机") || name.contains("智能") || name.contains("数据") || name.contains("软件")) return 1.0f;
         if (name.contains("电子") || name.contains("通信") || name.contains("自动化")) return 0.9f;
         if (name.contains("金融") || name.contains("经济")) return 0.8f;
         if (name.contains("机械") || name.contains("材料") || name.contains("土木")) return 0.7f;
         return 0.6f;
     }
} 